package com.temp.service.impl;

import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.temp.config.EpusdtConfig;
import com.temp.entity.*;
import com.temp.enumeration.CampaignStatus;
import com.temp.enumeration.PayStatus;
import com.temp.enumeration.PayType;
import com.temp.enumeration.VerifyResult;
import com.temp.exception.BaseException;
import com.temp.mapper.PaymentNotifyLogMapper;
import com.temp.mapper.PaymentOrderMapper;
import com.temp.service.CampaignService;
import com.temp.service.DonationService;
import com.temp.service.UserService;
import com.temp.utils.EpusdtSignUtil;
import com.temp.utils.ShiroUtils;
import com.temp.utils.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Slf4j
@Service
public class EpusdtService {

    // 添加常量定义
    private static final String DATE_TIME_PATTERN = "yyyy-MM-dd HH:mm:ss";
    private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern(DATE_TIME_PATTERN);
    private static final String CREATE_ORDER_PATH = "/CreateOrder";
    private static final String RESPONSE_OK = "ok";

    @Autowired
    private EpusdtConfig epusdtConfig;
    @Autowired
    private PaymentOrderMapper paymentOrderMapper;
    @Autowired
    private DonationService donationService;
    @Autowired
    private CampaignService campaignService;
    @Autowired
    private UserService userService;
    @Autowired
    private PaymentNotifyLogMapper paymentNotifyLogMapper;

    /**
     * 创建EPUSDT支付订单
     */
    @Transactional(rollbackFor = Exception.class)
    public PaymentOrder createPaymentOrder(PaymentOrder order) {
        // 1. 插入订单数据
        paymentOrderMapper.insert(order);

        try {
            // 2. 构建并发送请求（移出事务范围）
            JSONObject response = sendCreateOrderRequest(order);

            // 3. 解析响应并更新订单
            updateOrderFromResponse(order, response);
            paymentOrderMapper.updateById(order);

            return order;
        } catch (RuntimeException e) {
            // 明确抛出运行时异常以触发回滚
            throw e;
        } catch (Exception e) {
            log.error("创建TokenPay支付订单失败", e);
            throw new BaseException("apiMsg.createOrderError");
        }
    }

    /**
     * 发送创建订单请求（移出事务范围）
     */
    private JSONObject sendCreateOrderRequest(PaymentOrder order) {
        Map<String, Object> params = buildRequestParams(order);
        String signature = EpusdtSignUtil.generateSign(params, epusdtConfig.getApiKey());
        params.put("Signature", signature);

        String url = epusdtConfig.getApiUrl() + CREATE_ORDER_PATH;
        HttpRequest request = HttpUtil.createPost(url)
                .body(JSON.toJSONString(params))
                .contentType("application/json")
                .timeout(5000); // 添加超时设置

        HttpResponse response = request.execute();
        if (!response.isOk()) {
            throw new RuntimeException("TokenPay接口请求失败，状态码: " + response.getStatus());
        }

        JSONObject result = JSON.parseObject(response.body());
        if (!result.getBoolean("success")) {
            throw new RuntimeException("TokenPay创建订单失败: " + result.getString("message"));
        }

        return result.getJSONObject("info");
    }

    /**
     * 构建请求参数
     */
    private Map<String, Object> buildRequestParams(PaymentOrder order) {
        Map<String, Object> params = new HashMap<>();
        params.put("OutOrderId", order.getOrderId());
        params.put("OrderUserKey", order.getUserId().toString());
        BigDecimal scaledAmount = order.getAmount();
        params.put("ActualAmount", scaledAmount.stripTrailingZeros().toPlainString());
        params.put("Currency", order.getCurrencyName());
        params.put("NotifyUrl", order.getNotifyUrl());

        if (StringUtils.isNotBlank(order.getRedirectUrl())) {
            params.put("RedirectUrl", order.getRedirectUrl());
        }
        return params;
    }

    /**
     * 从响应更新订单信息
     */
    private void updateOrderFromResponse(PaymentOrder order, JSONObject data) {
        order.setTradeId(data.getString("Id"));
        order.setAmount(data.getBigDecimal("Amount"));
        order.setToAddress(data.getString("ToAddress"));
        order.setCurrencyName(data.getString("CurrencyName"));
        order.setBlockChainName(data.getString("BlockChainName"));
        order.setBaseCurrency(data.getString("BaseCurrency"));
        order.setExpirationTime(LocalDateTime.parse(
                data.getString("ExpireTime"), DATE_TIME_FORMATTER));
        order.setPaymentUrl(data.getString("data"));
        order.setQrCodeBase64(data.getString("QrCodeBase64"));
        order.setQrCodeLink(data.getString("QrCodeLink"));
        order.setStatus(PayStatus.WAITING_PAY.getCode());
    }

    /**
     * 处理EPUSDT回调
     */
    @Transactional
    public String handlePaymentNotify(JSONObject notifyData, String clientIp) {
        PaymentNotifyLog notifyLog = createNotifyLog(notifyData);

        try {
            // 1. IP白名单验证
            if (!isValidIp(clientIp)) {
                return handleInvalidRequest(notifyLog, "IP not allowed", "非法IP回调: {}", clientIp);
            }

            // 2. 签名验证
            if (!isValidSignature(notifyData)) {
                return handleInvalidRequest(notifyLog, "Signature verification failed",
                        "签名验证失败: {}", notifyData);
            }

            // 3. 查询并处理订单
            PaymentOrder order = findOrderByNotifyData(notifyData);
            if (order == null) {
                return handleInvalidRequest(notifyLog, "Order not found",
                        "订单不存在: {}", notifyData.getString("OutOrderId"));
            }

            // 4. 处理订单状态
            processOrderStatus(notifyData, order);

            // 记录成功日志
            return handleSuccess(notifyLog);
        } catch (Exception e) {
            log.error("处理支付回调异常", e);
            return handleException(notifyLog, e);
        }
    }

    /**
     * 处理订单状态
     */
    private void processOrderStatus(JSONObject notifyData, PaymentOrder order) {
        Integer status = notifyData.getInteger("Status");
        if (PayStatus.PAID_SUCCESS.getCode().equals(status)) {
            updateOrderForSuccessfulPayment(notifyData, order);

            if (PayType.USDT_TRC20.getKey().equals(notifyData.getString("Currency"))) {
                processDonation(order, notifyData.getString("BlockTransactionId"));
            }
        }
    }

    /**
     * 处理捐款逻辑
     */
    private void processDonation(PaymentOrder order, String blockTransactionId) {
        JSONObject extParam = JSON.parseObject(order.getExtParam());
        String campaignId = extParam.getString("campaignId");

        // 检查是否已存在相同交易ID的捐款
        Donation one = donationService.getOne(Wrappers.<Donation>lambdaQuery()
                .eq(Donation::getReceiptUrl, blockTransactionId)
                .eq(Donation::getUserId, order.getUserId()));

        if (one == null) {
            Campaign campaign = campaignService.getById(campaignId);
            if (campaign != null && !CampaignStatus.ENDED.getValue().equals(campaign.getStatus())) {
                performDonation(order.getUserId(), campaign, order.getAmount(), blockTransactionId);
            }
        }
    }

    /**
     * 执行捐款操作 - 使用更细粒度的事务控制
     */
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void performDonation(Long userId, Campaign campaign, BigDecimal amount, String blockTransactionId) {
        // 使用悲观锁或乐观锁防止并发问题
        Campaign lockedCampaign = campaignService.getCampaignForUpdate(campaign.getId());
        if (lockedCampaign == null || CampaignStatus.ENDED.getValue().equals(lockedCampaign.getStatus())) {
            return;
        }

        // 1. 创建捐款记录
        Donation donation = new Donation();
        donation.setUserId(userId);
        donation.setCampaignId(lockedCampaign.getId());
        donation.setAmount(amount);
        donation.setReceiptUrl(blockTransactionId);
        donation.setBeneficiaryId(lockedCampaign.getUserId());
        donationService.save(donation);

        // 2. 更新活动当前金额
        BigDecimal newAmount = lockedCampaign.getCurrentAmount().add(amount);
        lockedCampaign.setCurrentAmount(newAmount);

        // 3. 更新用户余额
        userService.updateUserBalance(lockedCampaign.getUserId(), amount);

        // 4. 检查是否达到目标金额
        if (newAmount.compareTo(lockedCampaign.getGoalAmount()) >= 0) {
            lockedCampaign.setStatus(CampaignStatus.ENDED.getValue());
        }
        lockedCampaign.setProgress(null);
        // 5. 更新活动
        campaignService.updateById(lockedCampaign);
    }

    // 以下是一些辅助方法的示例实现
    private PaymentNotifyLog createNotifyLog(JSONObject notifyData) {
        PaymentNotifyLog notifyLog = new PaymentNotifyLog();
        notifyLog.setOrderId(notifyData.getString("OutOrderId"));
        notifyLog.setTradeId(notifyData.getString("Id"));
        notifyLog.setStatus(notifyData.getInteger("Status"));
        notifyLog.setNotifyTime(LocalDateTime.now());
        notifyLog.setRequestBody(notifyData.toJSONString());
        return notifyLog;
    }

    private boolean isValidIp(String clientIp) {
        return epusdtConfig.getCallbackIp().equals(clientIp);
    }

    private boolean isValidSignature(JSONObject notifyData) {
        return EpusdtSignUtil.verifySign(notifyData, epusdtConfig.getApiKey());
    }

    private PaymentOrder findOrderByNotifyData(JSONObject notifyData) {
        return paymentOrderMapper.selectOne(Wrappers.<PaymentOrder>lambdaQuery()
                .eq(PaymentOrder::getOrderId, notifyData.getString("OutOrderId"))
                .eq(PaymentOrder::getTradeId, notifyData.getString("Id")));
    }

    private String handleInvalidRequest(PaymentNotifyLog notifyLog, String responseBody, String logMessage, Object... logParams) {
        log.warn(logMessage, logParams);
        notifyLog.setVerifyResult(VerifyResult.FAILED.getCode());
        notifyLog.setResponseBody(responseBody);
        paymentNotifyLogMapper.insert(notifyLog);
        return responseBody;
    }

    private String handleSuccess(PaymentNotifyLog notifyLog) {
        notifyLog.setVerifyResult(VerifyResult.SUCCESS.getCode());
        notifyLog.setResponseBody(RESPONSE_OK);
        paymentNotifyLogMapper.insert(notifyLog);
        return RESPONSE_OK;
    }

    private String handleException(PaymentNotifyLog notifyLog, Exception e) {
        notifyLog.setVerifyResult(VerifyResult.FAILED.getCode());
        notifyLog.setResponseBody("Error: " + e.getMessage());
        paymentNotifyLogMapper.insert(notifyLog);
        return "Error: " + e.getMessage();
    }

    private void updateOrderForSuccessfulPayment(JSONObject notifyData, PaymentOrder order) {
        order.setStatus(PayStatus.PAID_SUCCESS.getCode());
        order.setBlockTransactionId(notifyData.getString("BlockTransactionId"));
        order.setPayTime(LocalDateTime.parse(
                notifyData.getString("PayTime"), DATE_TIME_FORMATTER));
        order.setFromAddress(notifyData.getString("FromAddress"));
        paymentOrderMapper.updateById(order);
    }

    /**
     * 查询订单状态
     */
    public PaymentOrder queryOrderStatus(String orderId) {
        User user = ShiroUtils.getUser();
        return paymentOrderMapper.findPaymentViewByOrderId(orderId, user.getId());
    }
}